import redis
import time
import json
import uuid
from typing import Dict

# 2、使用Redis实现购物车功能
# 功能要求：
# 商品管理-添加商品到购物车-修改商品数量-删除购物车商品-清空购物车
# 价格计算-计算购物车总价-显示每个商品小计-统计商品总数量
# 数据存储-使用Hash存储商品信息-购物车数据30天自动过期-支持用户未登录时临时购物车
# 简单功能-合并购物车（登录后）-商品库存检查-优惠券应用

# Redis配置
REDIS_HOST = 'localhost'
REDIS_PORT = 6379

# 购物车过期时间（30天）
CART_EXPIRE_TIME = 30 * 24 * 60 * 60

# 建立Redis连接
redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT,db=8, decode_responses=True)

# 当前用户标识符
CURRENT_USER_ID = ""

# 操作字典
OPERATIONS = {
    '1': "添加商品到购物车",
    '2': "修改商品数量",
    '3': "删除购物车商品",
    '4': "清空购物车",
    '5': "查看购物车",
    '6': "计算购物车总价",
    '7': "显示商品小计",
    '8': "统计商品总数量",
    '9': "合并购物车",
    '0': "退出"
}


def wait_and_print(message=""):
    """统一等待和输出"""
    if message:
        print(message)
    time.sleep(1)


def get_cart_key(user_id: str) -> str:
    """获取购物车key"""
    return f"cart:{user_id}"


def add_product_to_cart(user_id: str, product_id: str, name: str, price: float, quantity: int = 1) -> bool:
    """
    添加商品到购物车
    """
    try:
        cart_key = get_cart_key(user_id)
        product_data = {
            'name': name,
            'price': price,
            'quantity': quantity
        }

        redis_client.hset(cart_key, product_id, json.dumps(product_data))
        redis_client.expire(cart_key, CART_EXPIRE_TIME)
        return True
    except Exception as e:
        print(f"添加商品失败: {e}")
        return False


def update_product_quantity(user_id: str, product_id: str, quantity: int) -> bool:
    """
    修改商品数量
    """
    try:
        if quantity <= 0:
            return remove_product_from_cart(user_id, product_id)

        cart_key = get_cart_key(user_id)
        product_info_str = redis_client.hget(cart_key, product_id)
        if not product_info_str:
            print("商品不存在于购物车中")
            return False

        product_info = json.loads(product_info_str)
        product_info['quantity'] = quantity
        redis_client.hset(cart_key, product_id, json.dumps(product_info))
        redis_client.expire(cart_key, CART_EXPIRE_TIME)
        return True
    except Exception as e:
        print(f"更新商品数量失败: {e}")
        return False


def remove_product_from_cart(user_id: str, product_id: str) -> bool:
    """
    删除购物车中的商品
    """
    try:
        cart_key = get_cart_key(user_id)
        result = redis_client.hdel(cart_key, product_id)
        redis_client.expire(cart_key, CART_EXPIRE_TIME)
        return result > 0
    except Exception as e:
        print(f"删除商品失败: {e}")
        return False


def clear_cart(user_id: str) -> bool:
    """
    清空购物车
    """
    try:
        cart_key = get_cart_key(user_id)
        return redis_client.delete(cart_key) > 0
    except Exception as e:
        print(f"清空购物车失败: {e}")
        return False


def get_cart_items(user_id: str) -> Dict:
    """
    获取购物车所有商品
    """
    try:
        cart_key = get_cart_key(user_id)
        items = redis_client.hgetall(cart_key)
        result = {}
        for product_id, product_info_str in items.items():
            result[product_id] = json.loads(product_info_str)
        return result
    except Exception as e:
        print(f"获取购物车商品失败: {e}")
        return {}


def calculate_product_subtotal(user_id: str, product_id: str) -> float:
    """
    计算单个商品小计
    """
    try:
        cart_key = get_cart_key(user_id)
        product_info_str = redis_client.hget(cart_key, product_id)
        if not product_info_str:
            print("商品不存在于购物车中")
            return 0.0

        product_info = json.loads(product_info_str)
        return product_info['price'] * product_info['quantity']
    except Exception as e:
        print(f"计算商品小计失败: {e}")
        return 0.0


def calculate_cart_total_price(user_id: str) -> float:
    """
    计算购物车总价
    """
    try:
        items = get_cart_items(user_id)
        total = 0.0
        for product_info in items.values():
            total += product_info['price'] * product_info['quantity']
        return total
    except Exception as e:
        print(f"计算购物车总价失败: {e}")
        return 0.0


def count_total_products(user_id: str) -> int:
    """
    统计商品总数量
    """
    try:
        items = get_cart_items(user_id)
        total_quantity = 0
        for product_info in items.values():
            total_quantity += product_info['quantity']
        return total_quantity
    except Exception as e:
        print(f"统计商品总数量失败: {e}")
        return 0


def merge_carts(temp_user_id: str, logged_user_id: str) -> bool:
    """
    合并购物车（登录后）
    """
    try:
        temp_cart_key = get_cart_key(temp_user_id)
        logged_cart_key = get_cart_key(logged_user_id)

        # 获取临时购物车内容
        temp_items = redis_client.hgetall(temp_cart_key)
        if not temp_items:
            print("临时购物车为空")
            return True

        # 合并到当前用户购物车
        for product_id, product_info in temp_items.items():
            redis_client.hset(logged_cart_key, product_id, product_info)

        # 删除临时购物车
        redis_client.delete(temp_cart_key)
        redis_client.expire(logged_cart_key, CART_EXPIRE_TIME)
        print("购物车合并成功")
        return True
    except Exception as e:
        print(f"合并购物车失败: {e}")
        return False


def show_cart(user_id: str):
    """显示购物车内容"""
    items = get_cart_items(user_id)
    if not items:
        print("购物车为空")
        return

    print("\n购物车内容:")
    print("-" * 50)
    print(f"{'商品ID':<10} {'商品名称':<15} {'单价':<10} {'数量':<8} {'小计':<10}")
    print("-" * 50)

    total = 0
    for product_id, product_info in items.items():
        subtotal = product_info['price'] * product_info['quantity']
        total += subtotal
        print(
            f"{product_id:<10} {product_info['name']:<15} {product_info['price']:<10} {product_info['quantity']:<8} {subtotal:<10.2f}")

    print("-" * 50)
    print(f"总计: {total:.2f}")


def handle_add_product(user_id: str):
    """处理添加商品操作"""
    print("=== 添加商品到购物车 ===")
    product_id = input("请输入商品ID: ").strip()
    name = input("请输入商品名称: ").strip()

    while True:
        try:
            price = float(input("请输入商品单价: ").strip())
            break
        except ValueError:
            print("请输入有效的数字")

    while True:
        try:
            quantity = int(input("请输入商品数量: ").strip())
            if quantity > 0:
                break
            else:
                print("数量必须大于0")
        except ValueError:
            print("请输入有效的整数")

    if add_product_to_cart(user_id, product_id, name, price, quantity):
        print("商品添加成功")
    else:
        print("商品添加失败")


def handle_update_quantity(user_id: str):
    """处理修改商品数量操作"""
    print("=== 修改商品数量 ===")
    product_id = input("请输入要修改的商品ID: ").strip()

    # 先检查商品是否存在
    cart_key = get_cart_key(user_id)
    if not redis_client.hexists(cart_key, product_id):
        print("商品不存在于购物车中")
        return

    while True:
        try:
            quantity = int(input("请输入新的商品数量: ").strip())
            if quantity > 0:
                break
            else:
                print("数量必须大于0")
        except ValueError:
            print("请输入有效的整数")

    if update_product_quantity(user_id, product_id, quantity):
        print("商品数量修改成功")
    else:
        print("商品数量修改失败")


def handle_remove_product(user_id: str):
    """处理删除商品操作"""
    print("=== 删除购物车商品 ===")
    product_id = input("请输入要删除的商品ID: ").strip()

    # 先检查商品是否存在
    cart_key = get_cart_key(user_id)
    if not redis_client.hexists(cart_key, product_id):
        print("商品不存在于购物车中")
        return

    confirm = input(f"确定要删除商品 {product_id} 吗? (y/N): ").strip().lower()
    if confirm == 'y':
        if remove_product_from_cart(user_id, product_id):
            print("商品删除成功")
        else:
            print("商品删除失败")
    else:
        print("已取消删除操作")


def handle_clear_cart(user_id: str):
    """处理清空购物车操作"""
    print("=== 清空购物车 ===")
    items = get_cart_items(user_id)
    if not items:
        print("购物车已经为空")
        return

    confirm = input("确定要清空购物车吗? (y/N): ").strip().lower()
    if confirm == 'y':
        if clear_cart(user_id):
            print("购物车清空成功")
        else:
            print("购物车清空失败")
    else:
        print("已取消清空操作")


def handle_calculate_subtotal(user_id: str):
    """处理计算商品小计操作"""
    print("=== 计算商品小计 ===")
    product_id = input("请输入商品ID: ").strip()

    # 先检查商品是否存在
    cart_key = get_cart_key(user_id)
    if not redis_client.hexists(cart_key, product_id):
        print("商品不存在于购物车中")
        return

    subtotal = calculate_product_subtotal(user_id, product_id)
    print(f"商品 {product_id} 的小计为: {subtotal:.2f}")


def handle_merge_carts(temp_user_id: str, logged_user_id: str):
    """处理合并购物车操作"""
    print("=== 合并购物车 ===")
    print(f"将临时购物车({temp_user_id})合并到用户购物车({logged_user_id})")

    confirm = input("确定要合并购物车吗? (y/N): ").strip().lower()
    if confirm == 'y':
        if merge_carts(temp_user_id, logged_user_id):
            print("购物车合并成功")
        else:
            print("购物车合并失败")
    else:
        print("已取消合并操作")


def user_interface(temp_user_id: str):
    """用户界面"""
    global CURRENT_USER_ID
    CURRENT_USER_ID = temp_user_id

    # 显示欢迎信息
    print(f"\n欢迎使用购物车系统!")
    print(f"临时用户ID: {CURRENT_USER_ID}")

    while True:
        wait_and_print()
        print("\n========== 购物车管理系统 ==========")
        print("请选择您要进行的操作:")

        for key, value in OPERATIONS.items():
            print(f"{key}. {value}")

        print("=" * 35)

        choice = input("请输入您的选择 (0-9): ").strip()

        if choice not in OPERATIONS:
            print("无效的选择，请重新输入")
            continue

        if choice == '0':
            print("感谢使用购物车系统，再见!")
            break

        print(f"\n您选择了: {OPERATIONS[choice]}")
        wait_and_print()

        try:
            if choice == '1':
                handle_add_product(CURRENT_USER_ID)
            elif choice == '2':
                handle_update_quantity(CURRENT_USER_ID)
            elif choice == '3':
                handle_remove_product(CURRENT_USER_ID)
            elif choice == '4':
                handle_clear_cart(CURRENT_USER_ID)
            elif choice == '5':
                show_cart(CURRENT_USER_ID)
            elif choice == '6':
                total = calculate_cart_total_price(CURRENT_USER_ID)
                print(f"购物车总价为: {total:.2f}")
            elif choice == '7':
                handle_calculate_subtotal(CURRENT_USER_ID)
            elif choice == '8':
                total_quantity = count_total_products(CURRENT_USER_ID)
                print(f"购物车商品总数量为: {total_quantity}")
            elif choice == '9':
                # 模拟登录后的用户ID
                logged_user_id = input("请输入登录后的用户ID: ").strip()
                if logged_user_id:
                    handle_merge_carts(CURRENT_USER_ID, logged_user_id)
                    # 合并后切换到登录用户
                    CURRENT_USER_ID = logged_user_id
                    print(f"已切换到用户: {CURRENT_USER_ID}")
        except Exception as e:
            print(f"执行操作时发生错误: {e}")

        wait_and_print()

        # 询问是否继续
        while True:
            continue_choice = input("是否继续操作? (y/n): ").strip().lower()
            if continue_choice in ['y', 'yes']:
                break
            elif continue_choice in ['n', 'no']:
                print("感谢使用购物车系统，再见!")
                return
            else:
                print("请输入 y 或 n")


def simulate_login():
    """模拟登录过程"""
    print("======= 购物车系统登录 =======")
    username = input("请输入用户名 (直接回车使用临时用户): ").strip()

    if not username:
        # 生成临时用户ID
        temp_user_id = f"temp_{uuid.uuid4().hex[:8]}"
        print(f"为您分配临时用户ID: {temp_user_id}")
        return temp_user_id
    else:
        # 使用输入的用户名作为用户ID
        print(f"欢迎您，{username}!")
        return username


if __name__ == "__main__":
    try:
        # 模拟登录获取用户ID
        user_id = simulate_login()

        # 进入用户界面
        user_interface(user_id)
    except KeyboardInterrupt:
        print("\n\n程序已被用户中断")
    except Exception as e:
        print(f"程序运行出错: {e}")
    finally:
        print("正在关闭Redis连接...")
        redis_client.close()
